package com.hhxy.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hhxy.handler.exception.CustomException;
import com.hhxy.mapper.RoleMapper;
import com.hhxy.model.dto.AddRoleDto;
import com.hhxy.model.entity.Role;
import com.hhxy.model.entity.RoleMenu;
import com.hhxy.model.entity.UserRole;
import com.hhxy.model.vo.PageVo;
import com.hhxy.model.vo.RolePageInfoVo;
import com.hhxy.service.RoleMenuService;
import com.hhxy.service.RoleService;
import com.hhxy.service.UserRoleService;
import com.hhxy.utils.BeanCopyUtils;
import com.hhxy.utils.SecurityUtils;
import com.hhxy.utils.response.AppHttpCodeEnum;
import com.hhxy.utils.response.ResponseResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author ghp
 * @description 针对表【tb_role(角色信息表)】的数据库操作Service实现
 * @createDate 2023-04-25 11:58:52
 */
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    @Resource
    private RoleMenuService roleMenuService;

    @Resource
    private UserRoleService userRoleService;

    /**
     * 根据用户userId查询角色信息
     *
     * @return
     */
    @Override
    public List<String> selectRoleKeyByUserId() {
        // 判断当前用户是否是超级管理员
        if (SecurityUtils.isAdmin()) {
            // 是超级管理员，则返回admin
            List<String> roleKeys = new ArrayList<>();
            roleKeys.add("admin");
            return roleKeys;
        }
        // 不是超级管理员，则查询用户所具有的角色信息然后返回
        return getBaseMapper().selectRoleKeyByUserId(SecurityUtils.getUserId());
    }

    /**
     * 分页条件查询角色信息
     */
    @Override
    public ResponseResult list(Integer pageNum, Integer pageSize, String roleName, String status) {
        // 分页条件查询角色信息
        Page<Role> page = new Page<>(pageNum, pageSize);
        this.page(page, new LambdaQueryWrapper<Role>().like(StringUtils.hasText(roleName), Role::getRoleName, roleName).eq(StringUtils.hasText(status), Role::getStatus, status).orderByAsc(Role::getRoleSort));
        // 查寻角色对应的权限信息

        // 封装VO
        List<RolePageInfoVo> rolePageInfoVos = BeanCopyUtils.copyBeanList(page.getRecords(), RolePageInfoVo.class);
        return ResponseResult.okResult(new PageVo(rolePageInfoVos, page.getTotal()));
    }

    /**
     * 新增角色
     *
     * @param addRoleDto
     * @return
     */
    @Override
    @Transactional
    public ResponseResult add(AddRoleDto addRoleDto) {
        // 判断在已逻辑删除的记录中是否存在新增的记录
        Role role = this.getBaseMapper().selectDeletedRoleByName(addRoleDto.getRoleName());
        if (Objects.nonNull(role)){
            // 先删除，然后再新增
            this.getBaseMapper().deleteDeletedRoleByName(addRoleDto.getRoleName());
        }

        // 存储角色信息（操作tb_role表）
        boolean flag = this.save(BeanCopyUtils.copyBean(addRoleDto, Role.class));
        if (!flag) {
            throw new CustomException(AppHttpCodeEnum.SERVICE_INSERT_ERROR);
        }
        // 判断该角色是否有对应的菜单id
        if (Objects.isNull(addRoleDto.getMenuIds()) && addRoleDto.getMenuIds().length > 0) {
            // 菜单id不为空，则存储角色菜单表（操作tb_role_menu表）
            flag = insertRoleMenu(addRoleDto);
            if (!flag) {
                throw new CustomException(AppHttpCodeEnum.SERVICE_INSERT_ERROR);
            }
        }
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS_INSERT);
    }

    /**
     * 根据角色id修改角色信息
     *
     * @param addRoleDto
     * @return
     */
    @Override
    @Transactional
    public ResponseResult updateRoleById(AddRoleDto addRoleDto) {
        // 保存角色信息（操作tb_role表）
        boolean flag = this.updateById(BeanCopyUtils.copyBean(addRoleDto, Role.class));
        if (!flag) {
            throw new CustomException(AppHttpCodeEnum.SERVICE_UPDATE_ERROR);
        }
        // 删除之前的角色-菜单关系，然后再重新保存本次更新后的角色-菜单关系（操作tb_role_menu）
//        flag = deleteRoleMenuByRoleId(addRoleDto.getId());
        flag = deleteRelation(roleMenuService, addRoleDto.getId());
        if (!flag) {
            throw new CustomException(AppHttpCodeEnum.SERVICE_UPDATE_ERROR);
        }
        flag = this.insertRoleMenu(addRoleDto);
        if (!flag) {
            throw new CustomException(AppHttpCodeEnum.SERVICE_UPDATE_ERROR);
        }
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS_UPDATE);
    }

    /**
     * 根据角色id删除角色信息
     *
     * @param ids
     * @return
     */
    @Override
    @Transactional
    public ResponseResult deleteRoleByIds(Long[] ids) {
        // 删除角色信息（操作tb_role表）
        boolean flag = this.removeByIds(Arrays.asList(ids));
        if (!flag) {
            throw new CustomException(AppHttpCodeEnum.SERVICE_DELETE_ERROR);
        }
        // 删除角色与菜单关系信息（操作tb_role_menu表）
        for (Long id : ids) {
//            flag = deleteRoleMenuByRoleId(id);
            flag = deleteRelation(roleMenuService, id);
            if (!flag) {
                throw new CustomException(AppHttpCodeEnum.SERVICE_DELETE_ERROR);
            }
        }
        // 删除角色用户关系信息（操作tb_user_role表）
        for (Long id : ids) {
//            flag = deleteUserRoleByRoleId(id);
            flag = deleteRelation(userRoleService, id);
            if (!flag) {
                throw new CustomException(AppHttpCodeEnum.SERVICE_DELETE_ERROR);
            }
        }
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS_DELETE);
    }

    /**
     * 根据用户id查询出所有的角色信息
     *
     * @param id
     * @return
     */
    @Override
    public List<Long> selectRoleIdByUserId(Long id) {
        return this.getBaseMapper().selectRoleIdByUserId(id);
    }

    /**
     * 根据角色id删除 用户-角色 关系（已被抽取成一个公共的方法 {@link #deleteRelation}）
     */
    private boolean deleteUserRoleByRoleId(Long id) {
        // 判断是否存在记录（防止remove没有修改记录返回false,导致系统异常）
        int count = userRoleService.count(new LambdaQueryWrapper<UserRole>()
                .eq(UserRole::getRoleId, id));
        if (count == 0) {
            // 该角色对应的tb_user_role表中不存在 用户-角色 关系，不需要删除，直接返回true
            return true;
        }
        // 存在 用户-角色关系，直接删除
        return userRoleService.remove(new LambdaQueryWrapper<UserRole>()
                .eq(UserRole::getRoleId, id));
    }

    /**
     * 根据角色id删除 角色-菜单关系（已被抽取成一个公共的方法 {@link #deleteRelation}）
     *
     * @param id
     * @return
     */
    private boolean deleteRoleMenuByRoleId(Long id) {
        // 判断是否存在记录（防止remove没有修改记录返回false,导致系统异常）
        int count = roleMenuService.count(new LambdaQueryWrapper<RoleMenu>()
                .eq(RoleMenu::getRoleId, id));
        if (count == 0) {
            // 该角色对应的tb_role_menu表中不存在 role_menu 关系，不需要删除，直接返回true
            return true;
        }
        // 存在 role_menu 关系，则需要进行删除
        return roleMenuService.remove(new LambdaQueryWrapper<RoleMenu>()
                .eq(RoleMenu::getRoleId, id));
    }

    /**
     * 删除关系
     *
     * @param service
     * @param id
     * @return
     */
    private <T> boolean deleteRelation(IService<T> service, Long id) {
        int count = service.count(new QueryWrapper<T>().eq("role_id", id));
        if (count == 0) {
            return true;
        }
        return service.remove(new QueryWrapper<T>().eq("role_id", id));
    }

    /**
     * 存储角色与菜单的关系
     *
     * @param addRoleDto
     */
    private boolean insertRoleMenu(AddRoleDto addRoleDto) {
        // 构建你RoleMenu对象
        List<RoleMenu> roleMenuList = Arrays.stream(addRoleDto.getMenuIds()).map(menuId -> new RoleMenu(addRoleDto.getId(), menuId)).collect(Collectors.toList());
        // 将构建好的对象存储到 tb_role_menu 表中
        return roleMenuService.saveBatch(roleMenuList);
    }
}




